using System;
using System.Collections.Generic;
using System.Configuration;
using System.Reflection;
using Microsoft.Practices.Unity.Configuration;

namespace Microsoft.Practices.Unity.Interception
{
    public abstract class InterceptionConfigurationElement : UnityContainerExtensionConfigurationElement
    {
        [ConfigurationProperty("interceptionType")]
        public string InterceptionType
        {
            get { return (string)this["interceptionType"]; }
            set { this["interceptionType"] = value; }
        }

        [ConfigurationProperty("methods")]
        [ConfigurationCollection(typeof(InterceptionMethodConfigurationElementCollection), AddItemName = "method")]
        public InterceptionMethodConfigurationElementCollection Methods
        {
            get { return (InterceptionMethodConfigurationElementCollection)this["methods"]; }
        }

        public override void Configure(IUnityContainer container)
        {
            base.Configure(container);

            IInterceptionConfiguration config = container.Configure<IInterceptionConfiguration>();
            Type typeToIntercept = System.Type.GetType(InterceptionType, true);
            Type methodType = typeToIntercept;
            List<IInterceptionHandler> handlers = new List<IInterceptionHandler>();
            foreach (InterceptionMethodConfiguraitonElement method in Methods)
            {
                foreach (InterceptionHandlerConfiguraitonElement handler in method.Handlers)
                {
                    IInterceptionHandler handlerInstance = (IInterceptionHandler)Activator.CreateInstance(System.Type.GetType(handler.HandlerType, true));
                    handlers.Add(handlerInstance);
                }

                if (!string.IsNullOrEmpty(method.MethodType))
                    methodType = System.Type.GetType(method.MethodType, true);

                Register(config, typeToIntercept, methodType.GetMethod(method.Name), handlers.ToArray());
            }
        }

        public abstract void Register(IInterceptionConfiguration config,
                                      Type typeToIntercept,
                                      MethodInfo methodInfo,
                                      IInterceptionHandler[] handlers);
    }
}